package main

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/middlewar/middleware"
)

// 测试登录接口的详细功能
func TestLoginEndpoint(t *testing.T) {
	// 设置测试模式
	gin.SetMode(gin.TestMode)

	// 创建路由（模拟main.go中的路由设置）
	r := gin.New()
	r.Use(
		middleware.Recovery(),
		middleware.RequestLogger(),
		middleware.CORSMiddleware(),
	)

	// 公开路由
	public := r.Group("/api/public")
	{
		// 登录接口
		public.POST("/login", func(c *gin.Context) {
			var loginReq struct {
				Username string `json:"username" binding:"required"`
				Password string `json:"password" binding:"required"`
			}

			if err := c.ShouldBindJSON(&loginReq); err != nil {
				c.JSON(http.StatusBadRequest, gin.H{
					"error":     "invalid request",
					"details":   err.Error(),
					"requestID": c.GetString("requestID"),
				})
				return
			}

			// 简单的用户验证逻辑
			if loginReq.Username == "admin" && loginReq.Password == "admin123" {
				token, err := middleware.GenerateToken("admin", []string{"admin", "user"})
				if err != nil {
					c.JSON(http.StatusInternalServerError, gin.H{
						"error":     "failed to generate token",
						"requestID": c.GetString("requestID"),
					})
					return
				}

				c.JSON(http.StatusOK, gin.H{
					"message":   "login successful",
					"token":     token,
					"userID":    "admin",
					"roles":     []string{"admin", "user"},
					"requestID": c.GetString("requestID"),
				})
			} else if loginReq.Username == "user" && loginReq.Password == "user123" {
				token, err := middleware.GenerateToken("user", []string{"user"})
				if err != nil {
					c.JSON(http.StatusInternalServerError, gin.H{
						"error":     "failed to generate token",
						"requestID": c.GetString("requestID"),
					})
					return
				}

				c.JSON(http.StatusOK, gin.H{
					"message":   "login successful",
					"token":     token,
					"userID":    "user",
					"roles":     []string{"user"},
					"requestID": c.GetString("requestID"),
				})
			} else {
				c.JSON(http.StatusUnauthorized, gin.H{
					"error":     "invalid credentials",
					"requestID": c.GetString("requestID"),
				})
			}
		})
	}

	// 测试用例
	tests := []struct {
		name           string
		requestBody    string
		expectedStatus int
		checkResponse  func(t *testing.T, body string)
	}{
		{
			name:           "管理员登录成功",
			requestBody:    `{"username":"admin","password":"admin123"}`,
			expectedStatus: http.StatusOK,
			checkResponse: func(t *testing.T, body string) {
				var response map[string]interface{}
				if err := json.Unmarshal([]byte(body), &response); err != nil {
					t.Errorf("解析响应失败: %v", err)
					return
				}

				if response["message"] != "login successful" {
					t.Errorf("期望消息为 'login successful'，实际: %v", response["message"])
				}

				if response["userID"] != "admin" {
					t.Errorf("期望userID为 'admin'，实际: %v", response["userID"])
				}

				if token, ok := response["token"].(string); !ok || token == "" {
					t.Error("token应该是非空字符串")
				}

				if roles, ok := response["roles"].([]interface{}); !ok || len(roles) != 2 {
					t.Errorf("期望roles为包含2个元素的数组，实际: %v", response["roles"])
				}
			},
		},
		{
			name:           "普通用户登录成功",
			requestBody:    `{"username":"user","password":"user123"}`,
			expectedStatus: http.StatusOK,
			checkResponse: func(t *testing.T, body string) {
				var response map[string]interface{}
				if err := json.Unmarshal([]byte(body), &response); err != nil {
					t.Errorf("解析响应失败: %v", err)
					return
				}

				if response["userID"] != "user" {
					t.Errorf("期望userID为 'user'，实际: %v", response["userID"])
				}

				if roles, ok := response["roles"].([]interface{}); !ok || len(roles) != 1 {
					t.Errorf("期望roles为包含1个元素的数组，实际: %v", response["roles"])
				}
			},
		},
		{
			name:           "用户名或密码错误",
			requestBody:    `{"username":"admin","password":"wrongpassword"}`,
			expectedStatus: http.StatusUnauthorized,
			checkResponse: func(t *testing.T, body string) {
				var response map[string]interface{}
				if err := json.Unmarshal([]byte(body), &response); err != nil {
					t.Errorf("解析响应失败: %v", err)
					return
				}

				if response["error"] != "invalid credentials" {
					t.Errorf("期望错误为 'invalid credentials'，实际: %v", response["error"])
				}
			},
		},
		{
			name:           "缺少用户名",
			requestBody:    `{"password":"admin123"}`,
			expectedStatus: http.StatusBadRequest,
			checkResponse: func(t *testing.T, body string) {
				if !strings.Contains(body, "invalid request") {
					t.Errorf("响应应该包含 'invalid request'，实际: %s", body)
				}
			},
		},
		{
			name:           "缺少密码",
			requestBody:    `{"username":"admin"}`,
			expectedStatus: http.StatusBadRequest,
			checkResponse: func(t *testing.T, body string) {
				if !strings.Contains(body, "invalid request") {
					t.Errorf("响应应该包含 'invalid request'，实际: %s", body)
				}
			},
		},
		{
			name:           "无效的JSON格式",
			requestBody:    `{"username":"admin","password":}`,
			expectedStatus: http.StatusBadRequest,
			checkResponse: func(t *testing.T, body string) {
				if !strings.Contains(body, "invalid request") {
					t.Errorf("响应应该包含 'invalid request'，实际: %s", body)
				}
			},
		},
		{
			name:           "空请求体",
			requestBody:    `{}`,
			expectedStatus: http.StatusBadRequest,
			checkResponse: func(t *testing.T, body string) {
				if !strings.Contains(body, "invalid request") {
					t.Errorf("响应应该包含 'invalid request'，实际: %s", body)
				}
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := httptest.NewRecorder()
			req, err := http.NewRequest("POST", "/api/public/login", strings.NewReader(tt.requestBody))
			if err != nil {
				t.Fatalf("创建请求失败: %v", err)
			}
			req.Header.Set("Content-Type", "application/json")

			r.ServeHTTP(w, req)

			if w.Code != tt.expectedStatus {
				t.Errorf("期望状态码 %d，实际 %d", tt.expectedStatus, w.Code)
			}

			if tt.checkResponse != nil {
				tt.checkResponse(t, w.Body.String())
			}
		})
	}
}

// 测试登录后的token使用
func TestLoginAndUseToken(t *testing.T) {
	gin.SetMode(gin.TestMode)

	r := gin.New()
	r.Use(
		middleware.Recovery(),
		middleware.RequestLogger(),
		middleware.CORSMiddleware(),
	)

	// 公开路由 - 登录
	public := r.Group("/api/public")
	{
		public.POST("/login", func(c *gin.Context) {
			var loginReq struct {
				Username string `json:"username" binding:"required"`
				Password string `json:"password" binding:"required"`
			}

			if err := c.ShouldBindJSON(&loginReq); err != nil {
				c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
				return
			}

			if loginReq.Username == "admin" && loginReq.Password == "admin123" {
				token, _ := middleware.GenerateToken("admin", []string{"admin", "user"})
				c.JSON(http.StatusOK, gin.H{"token": token})
			} else {
				c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
			}
		})
	}

	// 需要认证的路由
	authenticated := r.Group("/api/auth")
	authenticated.Use(middleware.JWTAuth())
	{
		authenticated.GET("/profile", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{
				"userID": c.GetString("userID"),
				"roles":  c.MustGet("roles"),
			})
		})
	}

	t.Run("完整的登录和使用token流程", func(t *testing.T) {
		// 步骤1: 登录获取token
		loginBody := `{"username":"admin","password":"admin123"}`
		w1 := httptest.NewRecorder()
		req1, _ := http.NewRequest("POST", "/api/public/login", strings.NewReader(loginBody))
		req1.Header.Set("Content-Type", "application/json")

		r.ServeHTTP(w1, req1)

		if w1.Code != http.StatusOK {
			t.Fatalf("登录失败，状态码: %d，响应: %s", w1.Code, w1.Body.String())
		}

		var loginResp map[string]interface{}
		if err := json.Unmarshal(w1.Body.Bytes(), &loginResp); err != nil {
			t.Fatalf("解析登录响应失败: %v", err)
		}

		token, ok := loginResp["token"].(string)
		if !ok || token == "" {
			t.Fatal("未能获取到有效token")
		}

		t.Logf("✅ 登录成功，获取到token: %s", token[:20]+"...")

		// 步骤2: 使用token访问受保护的路由
		w2 := httptest.NewRecorder()
		req2, _ := http.NewRequest("GET", "/api/auth/profile", nil)
		req2.Header.Set("Authorization", "Bearer "+token)

		r.ServeHTTP(w2, req2)

		if w2.Code != http.StatusOK {
			t.Fatalf("访问受保护路由失败，状态码: %d，响应: %s", w2.Code, w2.Body.String())
		}

		var profileResp map[string]interface{}
		if err := json.Unmarshal(w2.Body.Bytes(), &profileResp); err != nil {
			t.Fatalf("解析profile响应失败: %v", err)
		}

		if profileResp["userID"] != "admin" {
			t.Errorf("期望userID为 'admin'，实际: %v", profileResp["userID"])
		}

		t.Logf("✅ 使用token访问成功，用户信息: %+v", profileResp)
	})
}
